# Modern.js

import { Badge } from '@theme';

[Modern.js](https://modernjs.dev/zh/guides/get-started/introduction.html) 是一个基于 React 的渐进式 Web 开发框架。在字节跳动内部，Modern.js 支撑了数千个 Web 应用的研发。

Module Federation 团队与 Modern.js 团队紧密合作，并提供 `@module-federation/modern-js` 插件来帮助用户在 Modern.js 中更好的使用 Module Federation。

## 支持

- modern.js ^2.56.1
- 包含服务器端渲染（SSR）

强烈推荐参考下列应用，它提供了 Modern.js 与 Module Federation 结合的最佳实践：

* [服务端渲染（SSR）](https://github.com/module-federation/core/tree/main/apps/modernjs-ssr)
* [组件级别数据获取](https://github.com/module-federation/core/tree/main/apps/modern-component-data-fetch)

## 快速开始

### 安装

你可以通过如下的命令安装插件：

import { PackageManagerTabs } from '@theme';

<PackageManagerTabs
  command={{
    npm: 'npm add @module-federation/modern-js --save',
    yarn: 'yarn add @module-federation/modern-js --save',
    pnpm: 'pnpm add @module-federation/modern-js --save',
    bun: 'bun add @module-federation/modern-js --save',
  }}
/>

### 应用插件

在 `modern.config.ts` 的 `plugins` 中应用此插件：

```ts title="modern.config.ts"
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';

export default defineConfig({
  dev: {
    port: 3005,
  },
  runtime: {
    router: true,
  },
  // moduleFederationPlugin 是 modern.js 的插件，可以对构建/运行时做一定的修改
  plugins: [appTools(), moduleFederationPlugin()],
});
```

随后创建 `module-federation.config.ts` 文件，并写入需要的配置：

```ts title="module-federation.config.ts"
import { createModuleFederationConfig } from '@module-federation/modern-js';
export default createModuleFederationConfig({
  name: 'host',
  remotes: {
    remote: 'remote@http://localhost:3006/mf-manifest.json',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
});
```

## 服务端渲染（SSR）

:::info 注意
为更好的性能体验，Module Federation X Modern.js SSR 仅支持 stream SSR 。
:::

在 SSR 场景与 CSR 场景中使用 Module Federation 没有任何区别，开发者保持按照原有的开发行为即可。

## 组件级别数据获取

参考[数据获取](../basic/data-fetch/index)。

其中 Modern.js 插件在 `@module-federation/modern-js/react` 重导出了 `@module-federation/bridge-react` ，因此你不需要额外安装。

## API

`@module-federation/modern-js` 在子路径 `runtime` 重导出了 `@module-federation/modern-js/runtime` ，你可以使用 `@module-federation/modern-js/runtime` 来获取 MF Runtime。

### createRemoteComponent <Badge type="danger">废弃</Badge>

::: danger
此 API 已被废弃，请使用[createLazyComponent](/practice/bridge/react-bridge/load-component.html#什么是-createlazycomponent) 。
:::

#### 如何迁移

createRemoteComponent 参数和 createLazyComponent 完全一致，区别在于 createLazyComponent API 需要注册插件后，通过实例调用。

```diff
- import { createRemoteComponent } from '@module-federation/modern-js/runtime';
+ import { getInstance } from '@module-federation/modern-js/runtime';
+ import { lazyLoadComponentPlugin } from '@module-federation/modern-js/react';

const instance = getInstance();
// 注册 lazyLoadComponentPlugin 插件后，instance 会自动添加 createLazyComponent API
instance.registerPlugins([lazyLoadComponentPlugin()]);

- const LazyComponent = createRemoteComponent({
+ const LazyComponent = instance.createLazyComponent({
  loader: () => import('remote/Image'),
  loading: <div>loading...</div>,
  fallback: ({ error }) => {
    console.error(error)
    return <div>fallback</div>;
  },
});

const App: FC = () => {
  return <>
    <LazyComponent />
  </>;
};
export default App;
```

### createRemoteSSRComponent <Badge type="danger">废弃</Badge>

::: danger
此 API 已被废弃，请使用[createLazyComponent](/practice/bridge/react-bridge/load-component.html#什么是-createlazycomponent) 。
:::

#### 如何迁移

同 [createRemoteComponent#如何迁移](#如何迁移)

## 配置

### ssr

- 类型：`false`
- 是否必填：否
- 默认值：`undefined`

`@module-federation/modern-js` 会根据 modern.js config 中的 `server.ssr` 来自动添加 SSR 相关的构建预设。

如果当前项目仅需要在 CSR 加载 MF ，那么可以设置 `ssr: false` 来帮助渐进式迁移。

```ts title='modern.config.ts'
import { appTools, defineConfig } from '@modern-js/app-tools';
import { moduleFederationPlugin } from '@module-federation/modern-js';

// https://modernjs.dev/en/configure/app/usage
export default defineConfig({
  dev: {
    port: 3050,
  },
  runtime: {
    router: true,
  },
  server: {
    ssr: {
      mode: 'stream',
    },
  },
  plugins: [
    appTools(),
    moduleFederationPlugin({ ssr: false })
  ],
});
```

### fetchServerQuery

- 类型：`Record<string, unknown>`
- 是否必填：否
- 默认值：`undefined`

如果发生降级，那么会向服务端发送一个 http 请求，此时可以通过此配置来添加请求的 query。
